package com.vividsolutions.jts.addons;

import java.util.ArrayList;
import java.util.List;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Polygon;

public class GeomEditor {
	public double tolerance = 10;

	public Geometry geom = null;
	public int type = 0;//1 = line,2 = polygon
	public List<Geometry> helper = new ArrayList<Geometry>();

	private GeometryFactory gf = new GeometryFactory();
	private List<Coordinate> coordinates = new ArrayList<Coordinate>();
	private Coordinate lastPoint;

	public GeomEditor() {
		type = 0;

	}

	public GeomEditor(Geometry geom) {
		this();
		this.geom = geom;
	}

	public GeomEditor(int type) {
		this();
		this.type = type;
	}

	public void setGeom(Geometry geom) {
		this.geom = geom;
	}

	public void start() {

	}

	private void updateHelper() {
		helper.clear();

		for (Coordinate point : coordinates) {
			helper.add(gf.createPoint(point));
		}

		if ((type == 1 && coordinates.size() > 1)
				|| (type == 2 && coordinates.size() == 2)) {
			helper.add(gf.createLineString(coordinates
					.toArray(new Coordinate[0])));
		} else if (type == 2 && coordinates.size() > 2) {
			List<Coordinate> temp = new ArrayList<Coordinate>(coordinates);
			fixRing(temp);
			helper.add(gf.createLinearRing(temp.toArray(new Coordinate[0])));
		}
	}

	public void addPoint(double x, double y) {
		Coordinate newCoord = new Coordinate(x, y);
		if (lastPoint != null) {
			if (tolerance > lastPoint.distance(newCoord)) {
				return;
			}
		}
		lastPoint = newCoord;
		coordinates.add(newCoord);
		updateHelper();
	}

	public Geometry finish() {
		Geometry newGeom = null;
		if (coordinates.size() <= type) {
			return null;
		}

		switch (type) {
		case 0:
			newGeom = gf.createPoint(coordinates.get(0));
			break;
		case 1:
			newGeom = gf.createLineString(coordinates
					.toArray(new Coordinate[0]));
			break;
		case 2:
			fixRing(coordinates);
			LinearRing shell = gf.createLinearRing(coordinates
					.toArray(new Coordinate[0]));
			newGeom = gf.createPolygon(shell, null);
			break;
		default:
			break;
		}

		if (newGeom.isValid()) {
			coordinates.clear();
			helper.clear();
			lastPoint = null;
			this.geom = newGeom;
			return this.geom;
		}
		return null;
	}

	public void removeLastPoint() {
		if (lastPoint != null) {
			coordinates.remove(lastPoint);
			lastPoint = null;
		} else if (coordinates.size() > 0) {
			coordinates.remove(coordinates.size() - 1);
		}
		updateHelper();
	}

	public static void fixRing(List<Coordinate> coords) {
		Coordinate first = coords.get(0);
		Coordinate last = coords.get(coords.size() - 1);
		if (!first.equals(last)) {
			coords.add((Coordinate) first.clone());
		}
	}

}
